extracting complex "single cycle" waveforms from buffer~

Dan Nigrin's icon

Looking for best approaches here. Say I have a buffer~ object, filled with a bit of silence of unknown length (maybe not *exactly* 0.0 values, but close), followed by a few seconds of a tone comprised of repeating waveforms. I hesitate to say "single cycle", as each cycle might be composed of multiple zero crossings - these are not single cycle (e.g. sines, trianges, sawtooths, etc..) in the purest sense - they're complex waveforms. I *do* know that each repeating cycle is 256 samples in length.

What would be the best approach in extracting the 256 samples that comprise this "single cycle"?

I've tried simply stripping the beginning silence using automated approaches, and then counting 256 samples, and though it sort of worked, it was not precise enough, not sure why. Possibly because the sound takes some time to steady, or perhaps because my silence stripping was not accurate enough.

When I visualize the buffer~, I can clearly see the repeating patterns, so I figure there should be some way of perhaps taking adjacent 256 sample buffers, and measuring the absolute difference between the corresponding samples in each buffer. The 256 sample range which generates the least total difference with the 256 sample ranges after it is the "winner"?

Before I start trying to code this, does this reasonable? Any other better solutions? I hope my explanation makes sense....

Source Audio's icon

Why not normalise the buffer, and start searching for first max sample level position and
following 256 samples.
Could work in case no other things beside the waveforms are getting into buffer,
like clicks pops or whatever.
Then it would be a matter of rotating the buffer to get the waveform in question.
For looping it it would actually not matter,
Are this "tones" composed of absolutely indentical cycles of 256 samples ?

Dan Nigrin's icon

Apologies for the non-reply, I never received an email update of your response!

That's a cool idea of just looking for the maximum values, hadn't thought of that. But I neglected to say that I do need to preserve the "start" position of the repeating waveform (which is at a zero crossing)... So that buffer rotation you mention would be required, but I'd have no way to know when I'd rotated the "correct" amount, as there can be multiple zero crossings...

And as far as the waveforms being absolutely identical - technically they should be (they're being generated by a digital synth playing a wavetable), but they're being recorded in the analog domain, so they may not be exactly identical. Close though.

Source Audio's icon

I would guess that first zerocrossing would be before the first peak in the waveform. Before rotating buffer, it would be the last zero crossing of the slice
of 256 samples.That would then be the starting sample of the waveform.
In theory...
I made a patch that uses peek~ to do that.
But it would be much more efficient if one used buffercopy.
I have external which does so , values set in samples.
It is a mod of el.buffet~ from Eric lyon.
it is only 32 bit though.
here is peek only version :

Max Patch
Copy patch and select New From Clipboard in Max.


If You'd like to try version with buffer copy, let me know.
I will upload it and external.

Dan Nigrin's icon

Thanks for that - nicely done. Re: efficiency and using an external version - thanks but not necessary, as speed/efficiency is not a requirement for my use case.

However - your approach won't work right for my need, see crudely drawn mockup of what my sample might look like. It starts with the silence as I mentioned, then the waveform begins and repeats. However, each repeating waveform may not have just one zero crossing. In your patch, you're assuming the peak is preceded by the first and only zero crossing. Not necessarily the case....

Roman Thilenius's icon

the shorter the cycles are, the better it will work to match against the "least total difference".

if a cycle is 10,000 samples long you might as well find the best match at 2 samples off.

Dan Nigrin's icon

Hi Roman - no each cycle is by definition only 256 samples long.

Source Audio's icon

The patch I posted should select the last and not only zero crossing.
But that is irrelevant, as You say the waveform could have several
zerocrossings between waveform start and first peak.
In that case it is difficult to set a rule - which zerocrossing
is the right one.
If silence were really the silence, and waveform starts
from it's real beginning, one could maybe try to take that into
calculation.
But extracting the right 256 samples is a least a good start.
Not knowing the context of the later usage,
can't make suggestions, but one could rotate few versions and decide later...

Dan Nigrin's icon

Thanks - perhaps I should give more information re: what I'm trying to do. I'm trying to extract the wavetables from the ROM of a synth. There are 128 "frames" for each wavetable (each frame is 256 samples), and there are many (roughly 60 off the top of my head) different wavetables.

I have an automated approach in Max that allows me to select each wavetable, and in turn, each frame of each wavetable, for playback (and in turn, recording into Max). So for each wavetable/frame, I would like to trim the recording to a single frame, and then reassemble those 128 frames into the original wavetable.

With that in mind, thinking about manually rotating each frame is not something I'm eager to do (128 x ~60 = ~7680 frames)....

Source Audio's icon

I see, in that case even searching for the peak value might not be helpful,
wavetable could have it's peak in the middle or anywhere within the 256 samples.

Dan Nigrin's icon

Exactly - I'll keep plugging away at it and see if I can figure it out. Thanks regardless for your ideas!